from django import forms
from django.core import validators
from web import models
from django.conf import settings
import random
from utils.tencent.sms import send_sms_single
from django_redis import get_redis_connection
from utils import encrypt
from web.forms.bootstarp import BootStrapForm


class LoginModelForm(BootStrapForm, forms.ModelForm):
    mobile_phone = forms.CharField(label="手机号",
                                   validators=[validators.RegexValidator(r'1[3456789]\d{9}$', message="手机号码格式错误")])
    password = forms.CharField(label="密码", widget=forms.PasswordInput,
                               max_length=64, min_length=8,
                               error_messages={'max_length': '密码长度不能大于64个字符',
                                               'min_length': '密码长度不能小于8个字符', })
    confirm_password = forms.CharField(label='重复密码', widget=forms.PasswordInput,
                                       max_length=64, min_length=8,
                                       error_messages={'max_length': '重复密码长度不能大于64个字符',
                                                       'min_length': '重复密码长度不能小于8个字符', })
    code = forms.CharField(label="验证码")

    # 全部钩子验证
    def clean_username(self):
        username = self.cleaned_data.get('username')

        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise validators.ValidationError('用户名已存在')
        return username

    def clean_mobile_phone(self):
        tel = self.cleaned_data.get('mobile_phone')
        exits = models.UserInfo.objects.filter(mobile_phone=tel).exists()
        if exits:
            raise forms.ValidationError('手机号已经存在')
        return tel

    def clean_email(self):
        email = self.cleaned_data.get('email')

        exits = models.UserInfo.objects.filter(email=email).exists()
        if exits:
            raise forms.ValidationError('邮箱已存在')
        return email

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        # 加密 & 返回
        return encrypt.md5(pwd)

    def clean_confirm_password(self):
        cleaned_data = super().clean()
        pwd1 = cleaned_data.get('password')
        pwd2 = encrypt.md5(cleaned_data.get('confirm_password'))
        if pwd1 != pwd2:
            raise forms.ValidationError('输入密码不一致')
        return pwd2

    def clean_code(self):
        code = self.cleaned_data.get('code')
        models_phone = self.cleaned_data.get('mobile_phone')
        # 判断手机号是否处理回调
        if not models_phone:
            return code
        # 连接redis
        conn = get_redis_connection()
        redis_code = conn.get(models_phone)
        if not redis_code:
            raise validators.ValidationError('验证码失效或未发送,请重新发送')
        # 字节转字符串
        redis_str_code = str(redis_code, encoding='utf-8')
        # 验证码多打了空格也可以通过
        if redis_str_code.strip() != code:
            print('来了')
            raise validators.ValidationError('验证码错误,请重新输入')
        return code

    class Meta:
        model = models.UserInfo
        fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']


class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label="手机号",
                                   validators=[validators.RegexValidator(r'1[3456789]\d{9}$', message="手机号码格式错误")])

    def __init__(self, request, *args, **kwargs):
        # 这里注意啦，一不小心忘记重写了
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        # 获取是否符合检查格式
        tpl = self.request.GET.get('tpl')

        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        # 如果没有符合则返回错误信息
        if not template_id:
            raise validators.ValidationError('短信模板错误')
        # 检查数据库中是否已有手机号
        tel = self.cleaned_data.get('mobile_phone')
        exits = models.UserInfo.objects.filter(mobile_phone=tel).exists()
        # 是否为登录状态
        if tpl == "login":
            if not exits:
                raise validators.ValidationError('手机号不存在')
        # 是否为注册状态
        else:
            if exits:
                raise forms.ValidationError('手机号已经存在')

        # 发短信 & 写redis
        code = random.randrange(1000, 9999)
        sms = send_sms_single(tel, template_id, [code, ])
        if sms['result'] != 0:
            raise validators.ValidationError("短信发送失败,{}".format(sms['errmsg']))
        print(code)
        # 验证写入redis(django-redis),获取连接1000线程池
        conn = get_redis_connection()
        conn.set(tel, code, ex=60)
        return tel


class LoginSMSForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label="手机号",
                                   validators=[validators.RegexValidator(r'1[3456789]\d{9}$', message="手机号码格式错误")])
    code = forms.CharField(label="验证码")

    def clean_mobile_phone(self):
        tel = self.cleaned_data.get('mobile_phone')
        # 不判断是否为空，自己传对象，方便后续获取用户所有值
        user_object = models.UserInfo.objects.filter(mobile_phone=tel).first()
        if not user_object:
            raise forms.ValidationError('手机号不存在')
        return user_object

    def clean_code(self):
        code = self.cleaned_data.get('code')
        models_phone = self.cleaned_data.get('mobile_phone')
        # 判断手机号是否处理回调
        if not models_phone:
            return code
        # 连接redis
        conn = get_redis_connection()
        redis_code = conn.get(models_phone.mobile_phone)
        if not redis_code:
            raise validators.ValidationError('验证码失效或未发送,请重新发送')
        # 字节转字符串
        redis_str_code = str(redis_code, encoding='utf-8')
        # 验证码多打了空格也可以通过
        if redis_str_code.strip() != code:
            raise validators.ValidationError('验证码错误,请重新输入')
        return code


class LoginForm(BootStrapForm, forms.Form):
    username = forms.CharField(label='邮箱或手机号')
    password = forms.CharField(label='密码', widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label="图片验证码")

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_code(self):
        # 通过session的值来获取到验证进行验证(需要request)
        code = self.cleaned_data.get('code')
        session_code = self.request.session.get('image_code')
        if not session_code:
            raise validators.ValidationError('验证码已过期,请重新获取')
        if code.strip().upper() != session_code.upper():
            raise validators.ValidationError('验证码输入错误')
        return code

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        # 加密 & 返回
        return encrypt.md5(pwd)


